using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace usm.SolDev.Common
{
    public class ProcessRunner : IDisposable
    {
        #region Private data
        Process compilerProcess = new Process();
        Object syncObject = new Object ();
        bool hasExited = true;
        bool execute;

        #endregion

        #region Constructors
        /// <summary>
        ///     Default constructor
        /// </summary>
        public ProcessRunner () 
        {
            compilerProcess.StartInfo = new ProcessStartInfo();

            compilerProcess.StartInfo.RedirectStandardOutput = true;
            compilerProcess.StartInfo.RedirectStandardInput = true;

            compilerProcess.StartInfo.CreateNoWindow = true;  // hidden
            compilerProcess.StartInfo.ErrorDialog = false;    // no error messages to display
            compilerProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            compilerProcess.StartInfo.UseShellExecute = false;
        }

        /// <summary>
        ///     Initialization process
        /// </summary>
        /// <param name="path">the full process path</param>
        /// <param name="parameters">parameters list to pass to the process</param>
        /// <param name="outputStream">the output stream parameter</param>
        public ProcessRunner(string path, string [] parameters, ref System.IO.StreamReader outputStream)
        {
            compilerProcess.StartInfo = new ProcessStartInfo(path);

            compilerProcess.StartInfo.RedirectStandardOutput = true;
            outputStream = compilerProcess.StandardOutput;
            
            compilerProcess.StartInfo.CreateNoWindow = true;  // hidden
            compilerProcess.StartInfo.ErrorDialog = false;    // no error messages to display
            compilerProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            compilerProcess.StartInfo.UseShellExecute = false;

        }

        /// <summary>
        ///     Initialization process
        /// </summary>
        /// <param name="path">the full process path</param>
        /// <param name="parameters">parameters list to pass to the process</param>
        /// <param name="outputStream">the output stream parameter</param>
        public ProcessRunner(string path, string[] parameters, ref System.IO.StreamWriter inputStream, ref System.IO.StreamReader outputStream)
        {
            compilerProcess.StartInfo = new ProcessStartInfo(path);

            compilerProcess.StartInfo.RedirectStandardOutput = true;
            outputStream = compilerProcess.StandardOutput;

            compilerProcess.StartInfo.RedirectStandardInput = true;
            inputStream = compilerProcess.StandardInput;

            compilerProcess.StartInfo.CreateNoWindow = true;  // hidden
            compilerProcess.StartInfo.ErrorDialog = false;    // no error messages to display
            compilerProcess.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
            compilerProcess.StartInfo.UseShellExecute = false;

        }

        #endregion

        #region Destructors
        /// <summary>
        ///     Kill the process if is running 
        /// </summary>
        public virtual void Dispose()
        {
            if (compilerProcess != null && compilerProcess.HasExited == false)
            {
                compilerProcess.Kill();
            }
        }
        #endregion

        #region Process managment
        /// <summary>
        ///     Start the compilation process 
        /// </summary>
        /// <returns>return the operation result</returns>
        public bool Start()
        {
            lock (syncObject)
            {
                if ((compilerProcess.Start()) == false)
                {
                    return false;
                }

                hasExited = false;
                return true;
            }
        }
        #endregion

        #region Properties
        /// <summary>
        ///     Return the has exited property
        /// </summary>
        public bool HasExited
        {
            get 
            {
                lock (syncObject)
                {
                    if (compilerProcess.HasExited == false)
                    {
                        compilerProcess.WaitForExit(1000);
                    }

                    hasExited = compilerProcess.HasExited;
                    return hasExited;
                }
                
            }
        }
        
        /// <summary>
        ///     Return the output stream of the running process
        /// </summary>
        public System.IO.StreamReader OutputStream
        {
            get 
            {
                compilerProcess.StartInfo.RedirectStandardOutput = true;
                return compilerProcess.StandardOutput; 
            }
        }

        /// <summary>
        ///     Return the input stream of the running process
        /// </summary>
        public System.IO.StreamWriter InputStream
        {
            get
            {
                compilerProcess.StartInfo.RedirectStandardInput = true;
                return compilerProcess.StandardInput;
            }
        }

        /// <summary>
        ///     The name of the application with path
        /// </summary>
        public string Application
        {
            get { return compilerProcess.StartInfo.FileName; }
            set { compilerProcess.StartInfo.FileName = value; }
        }

        /// <summary>
        ///     The arguments of the executed program
        /// </summary>
        public string Arguments
        {
            get { return compilerProcess.StartInfo.Arguments; }
            set { compilerProcess.StartInfo.Arguments = value; }
        }


        /// <summary>
        ///     The working folder of the process
        /// </summary>
        public string WorkingDirectory
        {
            get 
            {
                if (compilerProcess == null || compilerProcess.StartInfo == null)
                {
                    return null;
                }

                return compilerProcess.StartInfo.WorkingDirectory;
            }

            set
            {
                if (compilerProcess != null && compilerProcess.StartInfo != null)
                {
                    compilerProcess.StartInfo.WorkingDirectory = value;
                }
            }
        }
        

        /// <summary>
        ///     The exit code of the executed program
        /// </summary>
        public int ExitCode
        {
            get
            {
                if (compilerProcess == null)
                {
                    return -1;
                }

                return compilerProcess.ExitCode; 
            }
        }

        /// <summary>
        ///     Determines if the code should be also compiled
        /// </summary>
        public bool Execute
        {
            get { return execute; }
            set
            { 
                execute = value;
                int runIndex = Arguments.IndexOf(" -r ");
                if (execute)
                {
                    if (runIndex == -1)
                    {
                        Arguments = String.Format(" -r {0}", Arguments);
                    }
                }
                else
                {
                    if (runIndex != -1)
                    {
                        Arguments = Arguments.Replace(" -r ", "");
                    }
                }
            }
        }
        #endregion
    }
}
